package com.example.ricebibackend.service.impl;

import cn.hutool.core.io.FileUtil;
import com.alibaba.excel.EasyExcel;
import com.alibaba.excel.support.ExcelTypeEnum;
import com.example.ricebibackend.common.constants.ChartConstant;
import com.example.ricebibackend.common.errorcode.ServiceErrorCodeConstants;
import com.example.ricebibackend.common.exception.ServiceException;
import com.example.ricebibackend.controller.param.AnalysisParam;
import com.example.ricebibackend.dao.dataobject.ChartDO;
import com.example.ricebibackend.dao.mapper.ChartMapper;
import com.example.ricebibackend.service.AIService;
import com.example.ricebibackend.service.AnalysisService;
import com.example.ricebibackend.service.dto.AIResponseDTO;
import com.example.ricebibackend.service.dto.AnalysisAskDTO;
import jakarta.annotation.Resource;
import org.apache.commons.io.FilenameUtils;
import org.apache.commons.lang3.StringUtils;
import org.springframework.stereotype.Service;
import org.springframework.web.multipart.MultipartFile;

import java.io.IOException;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
import java.util.concurrent.CompletableFuture;

/**
 * 分析模块业务实现类
 * @author ricejson
 */
@Service
public class AnalysisServiceImpl implements AnalysisService {

    @Resource
    private AIService aiService;
    @Resource
    private ChartMapper chartMapper;

    @Override
    public AnalysisAskDTO analysisAskAsync(AnalysisParam param, MultipartFile file) {
        // 校验参数
        checkAnalysisAskParam(param, file);
        // excel数据压缩
        String compCsvData = doExcelDataCompress(file);
        // 直接保存数据
        String goal = param.getGoal();
        String chartType = param.getChartType();
        String chartName = param.getChartName();
        ChartDO chartDO = new ChartDO();
        chartDO.setChartName(chartName);
        chartDO.setChartType(chartType);
        chartDO.setGoal(goal);
        chartDO.setCsvData(compCsvData);
        chartDO.setUploadUserId(param.getUploadUserId());
        chartDO.setTaskStatus("waiting"); // 设置状态
        chartMapper.insert(chartDO);
        CompletableFuture.runAsync(() -> {
            // 修改数据库状态
            ChartDO updateBeforeGenChartDO = new ChartDO();
            updateBeforeGenChartDO.setId(chartDO.getId());
            updateBeforeGenChartDO.setTaskStatus("running");
            int effectedRows = chartMapper.updateById(updateBeforeGenChartDO);
            if (effectedRows == 0) {
                handleAnalysisSqlException(chartDO.getId());
                return;
            }
            // 调用AI获取结果
            AIResponseDTO aiResponseDTO = aiService.genAnalysisResultByAI(compCsvData, goal, chartType);
            String genData = aiResponseDTO.getChartData();
            String genResult = aiResponseDTO.getAnalysisResult();
            // 保存数据持久化
            ChartDO updateAfterGenChartDO = new ChartDO();
            updateAfterGenChartDO.setId(chartDO.getId());
            updateAfterGenChartDO.setGenData(genData);
            updateAfterGenChartDO.setGenResult(genResult);
            updateAfterGenChartDO.setTaskStatus("succeed");
            effectedRows = chartMapper.updateById(updateAfterGenChartDO);
            if (effectedRows == 0) {
                handleAnalysisSqlException(chartDO.getId());
                return;
            }
        });
        // 返回生成图表以及分析结论
        return new AnalysisAskDTO();
    }

    private void handleAnalysisSqlException(Long chartId) {
        // 设置数据库状态
        ChartDO errorChartDO = new ChartDO();
        errorChartDO.setId(chartId);
        errorChartDO.setTaskStatus("failed");
        chartMapper.updateById(errorChartDO);
        throw new ServiceException(ServiceErrorCodeConstants.ANALYSIS_UPDATE_STATUS_ERROR);
    }

    @Override
    public AnalysisAskDTO analysisAsk(AnalysisParam param, MultipartFile file) {
        // 校验参数
        checkAnalysisAskParam(param, file);
        // excel数据压缩
        String compCsvData = doExcelDataCompress(file);
        // 调用AI获取结果
        String goal = param.getGoal();
        String chartType = param.getChartType();
        String chartName = param.getChartName();
        AIResponseDTO aiResponseDTO = aiService.genAnalysisResultByAI(compCsvData, goal, chartType);
        String genData = aiResponseDTO.getChartData();
        String genResult = aiResponseDTO.getAnalysisResult();
        // 保存数据持久化
        ChartDO chartDO = new ChartDO();
        chartDO.setChartName(chartName);
        chartDO.setChartType(chartType);
        chartDO.setCsvData(compCsvData);
        chartDO.setGoal(goal);
        chartDO.setGenData(genData);
        chartDO.setGenResult(genResult);
        chartDO.setUploadUserId(param.getUploadUserId());
        chartMapper.insert(chartDO);
        // 返回生成图表以及分析结论
        AnalysisAskDTO analysisAskDTO = new AnalysisAskDTO();
        analysisAskDTO.setData(aiResponseDTO.getChartData());
        analysisAskDTO.setResult(aiResponseDTO.getAnalysisResult());
        return analysisAskDTO;
    }

    /**
     * 数据压缩：excel => csv文本
     * @param file 文件
     * @return 压缩后的csv格式数据
     */
    private String doExcelDataCompress(MultipartFile file) {
        List<Map<Integer, String>> data = null; // 同步读取
        try {
            data = EasyExcel.read(file.getInputStream())
                    .excelType(ExcelTypeEnum.XLSX) // excel类型
                    .sheet()
                    .headRowNumber(0) // 表头所在行
                    .doReadSync();
        } catch (IOException e) {
            throw new RuntimeException(e);
        }
        if (data == null || data.size() == 0) {
            throw new ServiceException(ServiceErrorCodeConstants.ANALYSIS_PARSE_EXCEL_ERROR);
        }
        StringBuilder resBuilder = new StringBuilder();
        LinkedHashMap<Integer, String> headMap = (LinkedHashMap<Integer, String>) data.get(0);
        resBuilder.append("表头数据为:")
                .append(StringUtils.join(headMap.values(), ','))
                .append("\n")
                .append("表体数据为:")
                .append("\n");
        for (int i = 1; i < data.size(); i++) {
            // 拼接表体数据
            LinkedHashMap<Integer, String> bodyMap = (LinkedHashMap<Integer, String>) data.get(i);
            resBuilder.append(StringUtils.join(bodyMap.values(), ','))
                    .append("\n");
        }
        return resBuilder.toString();
    }

    /**
     * 校验参数
     * @param param 相关参数
     * @param file 文件
     */
    private void checkAnalysisAskParam(AnalysisParam param, MultipartFile file) {
        // 针对相关参数进行校验
        String goal = param.getGoal();
        if (StringUtils.isBlank(goal)) {
            // 分析目标为空
            throw new ServiceException(ServiceErrorCodeConstants.ANALYSIS_PARAMS_GOAL_NULL);
        }
        Long uploadUserId = param.getUploadUserId();
        if (uploadUserId == null || uploadUserId < 0) {
            // 上传用户ID参数错误
            throw new ServiceException(ServiceErrorCodeConstants.ANALYSIS_PARAMS_UPLOAD_USER_ID_NULL);
        }
        String chartName = param.getChartName();
        if (StringUtils.isBlank(chartName)) {
            // 图表名称参数错误
            throw new ServiceException(ServiceErrorCodeConstants.ANALYSIS_PARAMS_CHART_NAME_NULL);
        }
        String chartType = param.getChartType();
        // 针对文件进行校验
        long fileSize = file.getSize();
        if (fileSize > ChartConstant.MAX_FILE_SIZE) {
            // 校验文件大小
            throw new ServiceException(ServiceErrorCodeConstants.CHART_FILE_EXCEED_MAX_SIZE);
        }
        String fileName = file.getOriginalFilename();
        String postfix = FilenameUtils.getExtension(fileName);
        if (".xlsx".equals(postfix)) {
            // 文件后缀不合法
            throw new ServiceException(ServiceErrorCodeConstants.CHART_FILE_POSTFIX_ERROR);
        }
    }
}
